///////////////////////////////////////////////////////////////////////////////
//    Copyright (c) 2021 CASTest Corporation Limited. All Rights Reserved    //
///////////////////////////////////////////////////////////////////////////////


#include "ExecutionEngine.h"

void ExecutionEngine::ExecMultiThreadLogicSim(){
    GetParallelPattern();
//    GetSerialPattern();
    size_t start_pattern_id = 0;
    size_t end_pattern_id = _pi_value_size;
    size_t num_thread = 1;
    ConstructDffMater(_pi_value_size);
    AllocLogicArray(_pi_value_size);

    int rest = _pi_value_size, id = 0, start = 0;
    int task_size = rest / MAX_THREAD_NUM == 0 ? 1 : rest / MAX_THREAD_NUM;
    vector<LevelEventContainer*> event_containers;
    while (rest > 0) {
        LevelEventContainer *levelEventContainer = new LevelEventContainer(_levels.size());
        event_containers.push_back(levelEventContainer);
        task_size = rest > task_size ? task_size : rest;
        rest -= task_size;
        _thread_pool->res[id ++] = _thread_pool->Submit(bind(&Simulation::LogicSim, this, start, start + task_size, levelEventContainer));
        start += task_size;
    }
    _thread_pool->WaitTasks(id);
    for(int i =0; i<event_containers.size(); i++){
        event_containers[i]->clear();
        delete event_containers[i];
    }


}

void ExecutionEngine::ExecMultiThreadFaultSim(vector<Fault*>& flist ) {
    int rest = flist.size(), id = 0, start = 0;
    int task_size = rest / MAX_THREAD_NUM == 0 ? 1 : rest / MAX_THREAD_NUM;
    vector<LevelEventContainer*> event_containers;

    while (rest > 0) {
        LevelEventContainer *levelEventContainer = new LevelEventContainer(_levels.size());
        event_containers.push_back(levelEventContainer);

        task_size = rest > task_size ? task_size : rest;
        rest -= task_size;
        _thread_pool->res[id ++] = _thread_pool->Submit(bind(&Simulation::SingleFaultSim, this, flist, levelEventContainer, start, start + task_size));
        start += task_size;
    }
    _thread_pool->WaitTasks(id);
    for(int i =0; i<event_containers.size(); i++){
        event_containers[i]->clear();
        delete event_containers[i];
    }

}

void ExecutionEngine::ExecNetlistParsing(Params &params) {
    cout << "===       Begin Parsing Netlist       ===" << endl;
    ParseNetlist(params.GetPrimitiveVyFile(),
                 params.GetCellVyFile());
//    ofstream ofs(params.GetParserReport());
//    PrintNetlistInfo(ofs);
//    PrintGateFromPI(ofs);
//    PrintLevelArray(ofs);
//    PrintCellInfo(ofs);
//    ofs.close();
    cout << "===     Complete Parsing Netlist      ===" << endl;
}

void ExecutionEngine::ExecFaultListGeneration(Params &params) {
    cout << "===     Begin Creating Fault List     ===" << endl;
    ofstream ofs(params.GetFaultFile());
    CreateCellFaultList();
    CreateCellEqvFaultList();
    PrintFaultList(ofs, _uflist);
    ofs.close();
    cout << "===   Complete Creating  Fault List   ===" << endl;
}

void ExecutionEngine::ExecStilReading(Params &params) {
    cout << "===      Start Reading STIL File      ===" << endl;
    ParseStilFile(params.GetExternalStilFile());
    cout << "===    Complete Reading  STIL File    ===" << endl;
}

void ExecutionEngine::ExecLogicSimulation(Params &params) {
    cout << "===  Start Running  Logic Simulation  ===" << endl;
    auto start_t = std::chrono::system_clock::now();
    ExecMultiThreadLogicSim();
    auto end_t = std::chrono::system_clock::now();
    double duration = Utils::GetSysTimeInSeconds(start_t, end_t);
    cout << "--------------------------------------" << endl;
    cout << "            LSIM REPORT               " << endl;
    cout << "--------------------------------------" << endl;
    cout << "    Logic Simulation Summary Report   " << endl;
    cout << "--------------------------------------" << endl;
    cout << "Pattern   Nums: " << _num_pattern << endl;
    // cout << "Failed Pattern: " << " " << endl;
    cout << "Time      Cost: " << duration << endl;
    cout << "--------------------------------------" << endl;
    cout << "--------------------------------------" << endl;
    cout << "=== Complete Running Logic Simulation ===" << endl;
}

void ExecutionEngine::ExecFaultSimulation(Params &params) {

    cout << "===  Start Running  Fault Simulation  ===" << endl;
    auto start_t = std::chrono::system_clock::now();

    ofstream ofs(params.GetFaultFile());
    auto uflist = GetUncollapsedFlist();
    auto cflist = GetCollapsedFlist();
    // Execute good simulation
    ExecMultiThreadLogicSim();
    // Execute faulty simulation
    ExecMultiThreadFaultSim(uflist);
    // Set equivalent fault status
    FaultStatus last_fault_status = UNDETECTED;
    for(auto f: uflist){
        if(f->GetFaultEqv() != "--"){
            last_fault_status = f->GetFaultStatus();
        } else{
            f->SetFaultStatus(last_fault_status);
        }
    }

    double cnt = 0;
    for (auto f: uflist) {
        if (f->GetFaultStatus() == DETECTED) {
            cnt ++;
        }
    }

    PrintFaultList(ofs, _uflist);
    ofs.close();
    auto end_t = std::chrono::system_clock::now();
    double duration = Utils::GetSysTimeInSeconds(start_t, end_t);

    cout << "--------------------------------------" << endl;
    cout << "            FSIM REPORT               " << endl;
    cout << "--------------------------------------" << endl;
    cout << "    Fault Simulation Summary Report   " << endl;
    cout << "--------------------------------------" << endl;
    cout << "Pattern   Nums: " << _num_pattern << endl;
    cout << "Faults    Nums: " << uflist.size() << endl;
    cout << "Fault Coverage: " << static_cast<double>(cnt / uflist.size()) * 100 << "%" << endl;
    cout << "Time      Cost: " << duration << endl;
    cout << "--------------------------------------" << endl;
    cout << "--------------------------------------" << endl;
    cout << "Max Thread Nums:               " << MAX_THREAD_NUM << endl;
    cout << "--------------------------------------" << endl;
    cout << "=== Complete Running Fault Simulation ===" << endl;
}
